package com.tianyu.inspection.service.api;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tianyu.inspection.entity.Pipeline;
import com.tianyu.inspection.entity.PipelinePoint;
import com.tianyu.inspection.entity.model.QueryMo;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.ui.ModelMap;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**********************************
 * @Author YSW
 * @Description 管线服务
 * @Date 2021/1/17 - 08:30
 **********************************/

public interface IPipelineService extends IBaseService<Pipeline> {

    /**
     * 加载管线点
     * @param pipelineFile 管线JSON文件
     * @return 管线点
     */
    default List<PipelinePoint> loadPipeline(MultipartFile pipelineFile) {
        if (Objects.requireNonNull(pipelineFile.getOriginalFilename()).endsWith("json")) {
            return loadPipelineFromJson(pipelineFile);
        } else if (Objects.requireNonNull(pipelineFile.getOriginalFilename()).endsWith("kml")) {
            return loadPipelineFromKml(pipelineFile);
        }
        return null;
    }


    /**
     * @param pipelineFile
     * @return
     */
    default List<PipelinePoint> loadPipelineFromKml(MultipartFile pipelineFile) {
        List<PipelinePoint> points = new ArrayList<>();
        try {
            Document doc = new SAXReader().read(pipelineFile.getInputStream());
            Element messages = doc.getRootElement().elements("Document").get(0);
            List<Element> elements = messages.elements("Placemark");
            if (!elements.isEmpty()) {
                Element element = elements.get(0);
                Element name = element.element("name");
                Element lineString = element.element("LineString");
                if (Objects.nonNull(lineString)) {
                    Element coordinates = lineString.element("coordinates");
                    String coordinateString = coordinates.getTextTrim();
                    List<String> list = Arrays.asList(coordinateString.split(" "));
                    AtomicInteger seq = new AtomicInteger(1);
                    list.forEach(point -> {
                        String[] params = point.split(",");
                        points.add(new PipelinePoint()
                                .setLng(Double.valueOf(params[0]))
                                .setLat(Double.valueOf(params[1]))
                                .setAlt(Float.valueOf(params[2]))
                                .setSeq(seq.getAndIncrement()));
                    });
                    return points;
                }
            }
        } catch (DocumentException | IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    default List<PipelinePoint> loadPipelineFromJson(MultipartFile pipelineFile) {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                        pipelineFile.getInputStream(), StandardCharsets.UTF_8))) {
            StringBuilder sb = new StringBuilder();
            String lineTxt;
            while ((lineTxt = reader.readLine()) != null) {
                sb.append(lineTxt);
            }
            List<PipelinePoint> points = JSONArray.parseArray(sb.toString(), PipelinePoint.class);
            AtomicInteger seq = new AtomicInteger(1);
            points.forEach(point -> {
                if (Objects.isNull(point.getAlt())) {
                    point.setAlt(0F);
                }
                point.setSeq(seq.getAndIncrement());
            });
            return points;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 存储管线点
     * @param pipelineFile 管线JSON文件
     * @param pipelineName
     * @param projectId 项目ID
     * @return 管线点
     */
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    default boolean ossPipelineSave(MultipartFile pipelineFile, String pipelineName, Integer projectId){
        List<PipelinePoint> pointList = loadPipeline(pipelineFile);
        return savePipeline(pipelineName, projectId, pointList);
    }

    /**
     * 存储管线点
     * @param jsonObject JSON对象
     * @return 管线点
     */
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    default boolean ossPipelineSaveByJson(JSONObject jsonObject){
        final Boolean isMultiple = jsonObject.getBoolean("isMultiple");
        final Integer projectId = jsonObject.getInteger("projectId");
        if (isMultiple){
            final JSONArray lines = jsonObject.getJSONArray("pipelineData");
            int result = 0;
            int i = 0;
            for (Object item : lines) {
                final JSONObject lineObj = new ObjectMapper().convertValue(item, JSONObject.class);
                final JSONArray line = lineObj.getJSONArray("line");
                List<PipelinePoint> pointList = JSONArray.parseArray(line.toJSONString(), PipelinePoint.class);
                String name = lineObj.getString("name");
                if (Objects.isNull(name)){
                    name = "未命名"+(i++);
                }
                if (savePipeline(name, projectId, pointList)) {
                    result += 1;
                }
            }
            if (result == lines.size()){
                return true;
            }else {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return false;
            }
        }else {
            final JSONObject pipelineData = jsonObject.getJSONObject("pipelineData");
            final JSONArray line = pipelineData.getJSONArray("line");
            List<PipelinePoint> pointList = JSONArray.parseArray(line.toJSONString(), PipelinePoint.class);
            String name = pipelineData.getString("name");
            if (Objects.isNull(name)){
                name = "未命名";
            }
            return savePipeline(name, projectId, pointList);
        }
    }

    /**
     * 保存管线
     * @param name
     * @param projectId
     * @param pointList
     * @return
     */
    boolean savePipeline(String name, Integer projectId, List<PipelinePoint> pointList);

    /**
     * 查询管线列表并获取Oss存储管线点Protobuf
     * @param queryMo 查询参数集
     * @return
     */
    IPage<Pipeline> getOssPipelineList(QueryMo queryMo);

    /**
     * 查询管线列表并获取Oss存储管线点Protobuf
     * @param queryMo 查询参数集
     * @return
     */
    IPage<Pipeline> getDbPipelineList(QueryMo queryMo);

    List<com.tianyu.inspection.entity.Pipeline> getLinesTree(QueryMo queryMo);

    List<Pipeline> getLinesTreeLevel(QueryMo queryMo, String parentId);

    JSONObject kmlObjectLoad(JSONObject kmlObject,Integer projectId,Integer userId);

    JSONObject kmlJsonLoadPrepare(JSONObject kmlObject);

    /**
     * 通过ID等参数查询一条数据
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return 单条记录结果
     */
    Pipeline selectOneDetails(QueryMo queryMo);

    /**
     * 通过ID删除一条数据
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return 是否操作成功
     */
    ModelMap deleteOne(QueryMo queryMo);
}
